跳到主要内容

4.2 添加设计文件

在Diamond软件面板上,选择File>New>File,进行新文件创建。

alt text
图4.2.1 创建新文件

在文件创建界面,选择合适的文件类型。本文添加Verilog HDL设计文件。选好类型,设置文件名称,名称需要与函数名一致,点击New,这样我们就创建了一个新的设计文件,然后我们就可以在设计文件中进行编程了。

alt text
图4.2.2 添加main文件

接下来按照同样的方法依次添加屏幕驱动文件。

alt text
图4.2.3 添加屏幕驱动文件

添加按键消抖文件

alt text
图4.2.4添加按键消抖文件

在新创建的Verilog文件中进行Verilog HDL代码编写。编写完成后,保存。IDE自动将模块更新到左侧Hierarchy(层次)窗口。

alt text
图4.2.5 编写代码

主程序:

module main (clk,rst,keya,keyb,keyc,keyd,oled_rst,oled_dcn,oled_clk,oled_dat);

input clk;
input rst;
input keya;
input keyb;
input keyc;
input keyd;
output oled_rst; //
output oled_dcn; //
output oled_clk; //
output oled_dat;
wire key_pulsea;
wire key_pulseb;
wire key_pulsec;
wire key_pulsed;
reg [7:0] shuzi1;
reg [7:0] shuzi2;
reg [7:0] shuzi3;
reg [7:0] shuzi4;
//当按键按下时产生一个高脉冲,数字加一
always @(posedge clk or negedge rst)
begin
if (!rst)
shuzi1 <= 1'b0;
else if (key_pulsea)
begin
if(shuzi1 >= 8'd9)
shuzi1 <= 1'b0;
else
shuzi1 <= shuzi1 + 1;
end
end

always @(posedge clk or negedge rst)
begin
if (!rst)
shuzi2 <= 1'b0;
else if (key_pulseb)
begin
if(shuzi2 >= 8'd9)
shuzi2 <= 1'b0;
else
shuzi2 <= shuzi2 + 1;
end
end

always @(posedge clk or negedge rst)
begin
if (!rst)
shuzi3 <= 1'b0;
else if (key_pulsec)
begin
if(shuzi3 >= 8'd9)
shuzi3 <= 1'b0;
else
shuzi3 <= shuzi3 + 1;
end
end

always @(posedge clk or negedge rst)
begin
if (!rst)
shuzi4 <= 1'b0;
else if (key_pulsed)
begin
if(shuzi4 >= 8'd9)
shuzi4 <= 1'b0;
else
shuzi4 <= shuzi4 + 1;
end
end

//例化消抖module,这里没有传递参数N,采用了默认的N=1
debounce u1 (
.clk (clk),
.rst (rst),
.key (keya),
.key_pulse (key_pulsea)
);
debounce u2 (
.clk (clk),
.rst (rst),
.key (keyb),
.key_pulse (key_pulseb)
);
debounce u3 (
.clk (clk),
.rst (rst),
.key (keyc),
.key_pulse (key_pulsec)
);
debounce u4 (
.clk (clk),
.rst (rst),
.key (keyd),
.key_pulse (key_pulsed)
);
OLED12864 OLED12864_u(
.clk(clk),
.rst_n(rst),
.shuzi4(shuzi4),
.shuzi3(shuzi3),
.shuzi2(shuzi2),
.shuzi1(shuzi1),
.oled_csn(),
.oled_rst(oled_rst),
.oled_dcn(oled_dcn),
.oled_clk(oled_clk),
.oled_dat(oled_dat)
);
endmodule

按钮:

module debounce (clk,rst,key,key_pulse);

parameter N = 1; //要消除的按键的数量

input clk;
input rst;
input [N-1:0] key; //输入的按键
output [N-1:0] key_pulse; //按键动作产生的脉冲

reg [N-1:0] key_rst_pre; //定义一个寄存器型变量存储上一个触发时的按键值
reg [N-1:0] key_rst; //定义一个寄存器变量储存储当前时刻触发的按键值

wire [N-1:0] key_edge; //检测到按键由高到低变化是产生一个高脉冲

//利用非阻塞赋值特点,将两个时钟触发时按键状态存储在两个寄存器变量中
always @(posedge clk or negedge rst)
begin
if (!rst) begin
key_rst <= {N{1'b1}}; //初始化时给key_rst赋值全为1,{}中表示N个1
key_rst_pre <= {N{1'b1}};
end
else begin
key_rst <= key; //第一个时钟上升沿触发之后key的值赋给key_rst,同时key_rst的值赋给key_rst_pre
key_rst_pre <= key_rst; //非阻塞赋值。相当于经过两个时钟触发,key_rst存储的是当前时刻key的值,key_rst_pre存储的是前一个时钟的key的值
end
end

assign key_edge = key_rst_pre & (~key_rst);//脉冲边沿检测。当key检测到下降沿时,key_edge产生一个时钟周期的高电平

reg [17:0] cnt; //产生延时所用的计数器,系统时钟12MHz,要延时20ms左右时间,至少需要18位计数器

//产生20ms延时,当检测到key_edge有效是计数器清零开始计数
always @(posedge clk or negedge rst)
begin
if(!rst)
cnt <= 18'h0;
else if(key_edge)
cnt <= 18'h0;
else
cnt <= cnt + 1'h1;
end
reg [N-1:0] key_sec_pre; //延时后检测电平寄存器变量
reg [N-1:0] key_sec;
//延时后检测key,如果按键状态变低产生一个时钟的高脉冲。如果按键状态是高的话说明按键无效
always @(posedge clk or negedge rst)
begin
if (!rst)
key_sec <= {N{1'b1}};
else if (cnt==18'h3ffff)
key_sec <= key;
end
always @(posedge clk or negedge rst)
begin
if (!rst)
key_sec_pre <= {N{1'b1}};
else
key_sec_pre <= key_sec;
end

assign key_pulse = key_sec_pre & (~key_sec);
endmodule